package com.bridge.controller;

import com.alibaba.fastjson.JSON;
import com.bridge.common.BaseResponse;
import com.bridge.enums.ErrorCodeEnum;
import com.bridge.model.SysDictConfig;
import com.bridge.service.IRedisHashService;
import com.bridge.utils.ValidatorUtil;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;


/**
 * 常用的方法：
 * 数据类型Hash字典
 * Hash底层存储数据的方式确实跟其他数据结构有点不同，其他数据结构几乎都是：Key-Value的存储，
 * 而Hash则是：Key – [Field-Value] 的存储，也就是说其他数据结构的Value一般是确切的值，而Hash的Value是一系列的键值对，
 * 通常我们是这样称呼Hash的存储的：大Key为实际的Key，小Key为Field，而具体的取值为Field对应的值value。
 * 实践：系统数据字典实时触发缓存存储
 * 1. put(H key, HK hashKey, HV value);   新增hashMap值。
 * 2. putAll(H key, Map<? extends HK,? extends HV> m)；以map集合的形式添加键值对。
 * 3. entries(H key)； 获取key的列表元素。
 * 4. get(H key, Object hashKey)； 获取变key中的指定field键是否有值,如果存在返回value，没有则返回null。
 * 5. keys(H key)； 获取key中的所有field列表。
 * 6. hasKey(H key, Object hashKey)；判断key是否有指定的field。
 * 7. delete(H key, Object... hashKeys)； 删除key中的field-value对，可以传入多个参数，删除多个field-value对。
 * 8. size(H key)；获取key的长度。
 * @author bridge
 *  2022/05/25/20:23
 */
@RestController
@RequestMapping("RedisHashController")
@Api(tags = "RedisHashController", description = "测试")
public class RedisHashController {

    private static final Logger log = LoggerFactory.getLogger(RedisHashController.class);

    @Resource
    private IRedisHashService redisHashService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    @ApiOperation("开始哈希Hash测试")
    @GetMapping(value = "/hashSet")
    public void hashSet() {
        log.info("----开始哈希Hash测试");
        final String key = "SpringBootRedis:Hash:Key:英雄联盟";
        redisTemplate.delete(key);

        HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
        hashOperations.put(key, "德玛西亚", "盖伦");
        hashOperations.put(key, "诺克萨斯", "德莱厄斯");

        Map<String, String> dataMap = Maps.newHashMap();
        dataMap.put("祖安", "蒙多");
        dataMap.put("艾欧尼亚", "艾瑞莉娅");
        hashOperations.putAll(key, dataMap);

        log.info("---哈希hash-获取列表元素： {} ", hashOperations.entries(key));
        log.info("---哈希hash-获取诺克萨斯的元素： {} ", hashOperations.get(key, "诺克萨斯"));
        log.info("---哈希hash-获取所有元素的field列表： {} ", hashOperations.keys(key));

        log.info("---哈希hash-祖安成员是否存在： {} ", hashOperations.hasKey(key, "祖安"));
        log.info("---哈希hash-艾欧尼亚成员是否存在： {} ", hashOperations.hasKey(key, "艾欧尼亚"));

        hashOperations.putIfAbsent(key, "暗影", "卡尔萨斯");
        log.info("---哈希hash-获取列表元素： {} ", hashOperations.entries(key));

        log.info("---哈希hash-删除元素德玛西亚、 诺克萨斯： {} ", hashOperations.delete(key, "德玛西亚", "诺克萨斯"));
        log.info("---哈希hash-获取列表元素： {} ", hashOperations.entries(key));

        log.info("---哈希hash-获取列表元素个数： {} ", hashOperations.size(key));
    }


    //==============================================系统数据字典实时触发缓存存储=================================================//


    /**
     * 添加数据字典及其对应的选项(field-value)
     * @param config config
     * @param result result
     */
    @ApiOperation("添加数据字典及其对应的选项")
    @PostMapping(value = "/addSysDictConfig")
    public BaseResponse<String> addSysDictConfig(@RequestBody @Validated SysDictConfig config, BindingResult result){
        List<FieldError> fieldErrors = ValidatorUtil.checkResult(result);
        if (!CollectionUtils.isEmpty(fieldErrors)){
            return new BaseResponse<>(ErrorCodeEnum.FAIL.getCode(), JSON.toJSONString(fieldErrors));
        }
        BaseResponse<String> response=new BaseResponse<>(ErrorCodeEnum.SUCCESS.getCode());
        try {
            redisHashService.addSysDictConfig(config);
        }catch (Exception e){
            response=new BaseResponse<>(ErrorCodeEnum.FAIL.getCode(),e.getMessage());
        }
        return response;
    }


    /**
     *获取缓存中所有的数据字典
     * @return 所有字典列表
     */
    @ApiOperation("获取缓存中所有的数据字典")
    @GetMapping(value = "getSysDictConfig")
    public BaseResponse<Map<String, List<SysDictConfig>>> getSysDictConfig(){
        BaseResponse<Map<String, List<SysDictConfig>>> response=new BaseResponse<>(ErrorCodeEnum.SUCCESS.getCode());
        try {
            response.setData(redisHashService.getSysDictConfig());
        }catch (Exception e){
            response=new BaseResponse<>(ErrorCodeEnum.FAIL.getCode(),e.getMessage());
        }
        return response;
    }


    /**
     * 获取缓存中某个特定编码下数据字典的取值列表
     * @param type 类型
     * @return 字典列表
     */
    @ApiOperation("获取缓存中某个特定编码下数据字典的取值列表")
    @GetMapping(value = "get/type")
    public BaseResponse<List<SysDictConfig>> getType(@RequestParam String type){
        BaseResponse<List<SysDictConfig>> response=new BaseResponse<>(ErrorCodeEnum.SUCCESS.getCode());
        try {
            response.setData(redisHashService.getByType(type));
        }catch (Exception e){
            response=new BaseResponse<>(ErrorCodeEnum.FAIL.getCode(),e.getMessage());
        }
        return response;
    }

    /**
     * 获取缓存中某个特定编码下数据字典的取值列表
     * @param type 类型
     * @return 字典列表
     */
    @ApiOperation("获取缓存中某个特定编码下数据字典的取值列表")
    @GetMapping(value = "update/type")
    public BaseResponse<List<SysDictConfig>> update(@RequestParam String type){
        BaseResponse<List<SysDictConfig>> response=new BaseResponse<>(ErrorCodeEnum.SUCCESS.getCode());
        try {
            response.setData(redisHashService.update(type));
        }catch (Exception e){
            response=new BaseResponse<>(ErrorCodeEnum.FAIL.getCode(),e.getMessage());
        }
        return response;
    }

}

